﻿using EBA.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EBA.Linq
{
    public class Hitable<T> : IHitable<T>
    {
        IQueryable<T> _Source;
        public Hitable(IQueryable<T> source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("IQueryable<T> source");
            }

            this._Source = source;
        }

        public IHitable<T> Where(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
        {
            this._Source = this._Source.Where(predicate);
            return this;
        }

        public IHitable<T> OrderBy<TKey>(System.Linq.Expressions.Expression<Func<T, TKey>> orderby)
        {
            this._Source = this._Source.OrderBy(orderby);
            return this;
        }

        public IHitable<T> ThenBy<TKey>(System.Linq.Expressions.Expression<Func<T, TKey>> orderby)
        {
            if (this._Source is IOrderedQueryable<T>)
            {
                this._Source = ((IOrderedQueryable<T>)this._Source).ThenBy(orderby);
            }
            else
            {
                this._Source = this._Source.OrderBy(orderby);
            }

            return this;
        }

        public IHitable<T> OrderByDescending<TKey>(System.Linq.Expressions.Expression<Func<T, TKey>> orderby)
        {

            this._Source = this._Source.OrderByDescending(orderby);


            return this;
        }

        public IHitable<T> ThenByDescending<TKey>(System.Linq.Expressions.Expression<Func<T, TKey>> orderby)
        {
            if (this._Source is IOrderedQueryable<T>)
            {
                this._Source = ((IOrderedQueryable<T>)this._Source).ThenByDescending(orderby);
            }
            else
            {
                this._Source = this._Source.OrderByDescending(orderby);
            }

            return this;
        }

        public Hits<T> Fetch(int index = 1, int size = int.MaxValue)
        {
            var totalHits = this._Source.Count();
            var skip = (index - 1) * size;
            var hits = new Hits<T>(this._Source.Skip(skip).Take(size));

            hits.TotalHits = totalHits;

            return hits;

        }


        public bool Any()
        {
            return this._Source.Any();
        }

        public bool Any(Func<T, bool> predicate)
        {
            return this._Source.Any(predicate);
        }

        public T FirstOrDefault()
        {
            return this._Source.FirstOrDefault();
        }

        public T FirstOrDefault(Func<T, bool> predicate)
        {
            return this._Source.FirstOrDefault(predicate);
        }

        public Hits<T> ToHits()
        {
            return this.Fetch();
        }

        public List<T> ToList()
        {
            return this._Source.ToList();
        }

        public IHitable<T> OrderBy(string orderby)
        {
            if (string.IsNullOrWhiteSpace(orderby) == false)
            {
                this._Source = this._Source.OrderBy(orderby);
            }
            return this;

        }

        public IHitable<T> OrderBy(string[] orderby)
        {
            if (orderby != null && orderby.Length > 0)
            {
                this._Source = this._Source.OrderBy(string.Join(",", orderby.ToArray()));
            }
            return this;

        }
    }
}
